#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h> //包含sockaddr_in结构
#include <unistd.h>
#include "sock.hpp"
#include <sys/epoll.h>
#include <functional>
#include <cstring>
#include <errno.h>
#include "err.hpp"
#include "log.hpp"
namespace epoll_ns
{
    using func_t = std::function<std::string(const std::string &)>;
    static const uint16_t gport = 8080;
    static const int size = 128;
    static const int defaultvalue = -1;
    static const int defalultnum = 64;
    class EpollServer
    {
    public:
        EpollServer(func_t func, uint16_t port = gport, int num = defalultnum)
            : _listenSock(-1), _port(port), _func(func), _epfd(defaultvalue), _num(num), _revs(nullptr)
        {
        }

        void initServer()
        {
            _listenSock = Sock::getSocket();
            Sock::Bind(_listenSock, _port);
            Sock::Listen(_listenSock);
            // 创建epoll模型
            _epfd = epoll_create(size);
            if (_epfd < 0)
            {
                logMessage(FATAL, "epoll create error %s", strerror(errno));
                exit(EPOLL_CREATE_ERR);
            }
            // 添加listenSock到epoll模型中
            struct epoll_event ev;
            ev.events = EPOLLIN;
            ev.data.fd = _listenSock;
            // int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
            epoll_ctl(_epfd, EPOLL_CTL_ADD, _listenSock, &ev);

            _revs = new struct epoll_event[_num];
            logMessage(NORMAL, "init server success");
            
        }

        void start()
        {
            for (;;)
            {
                // int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
                int timeout = 1000;
                int n = epoll_wait(_epfd, _revs, _num, timeout); // LT 模式
                cout << n << endl;
                switch (n)
                {
                case 0:
                    logMessage(NORMAL, "timeout ...");
                    break;
                case -1:
                    logMessage(WARNING, "epoll_wait failed, code: %d, errstring: %s", errno, strerror(errno));
                    break;
                default:
                    logMessage(NORMAL, "have event ready");
                    HandlerEvent(n);
                    break;
                }
            }
        }

        void HandlerEvent(int readyNum)
        {
            logMessage(DEBUG, "HandlerEvent in");
            for (int i = 0; i < readyNum; i++)
            {
                uint32_t events = _revs[i].events;
                int sock = _revs[i].data.fd;
                // 判断sock是不是listenSock ,同时判断返回的事件是否有EPOLLIN
                if (sock == _listenSock && (events & EPOLLIN))
                {
                    std::string clientip;
                    uint16_t clientport;
                    int fd = Sock::Accept(sock, &clientip, &clientport);
                    if (fd < 0)
                    {
                        logMessage(WARNING, "accept error");
                        continue;
                    }
                    // 成功获取fd成功，可以直接读取嘛？不可以，放入epoll模型啊
                    struct epoll_event ev;
                    ev.events = EPOLLIN;
                    ev.data.fd = fd;
                    epoll_ctl(_epfd, EPOLL_CTL_ADD, fd, &ev);
                }
                else if (events & EPOLLIN)
                {
                    // 普通的读事件就绪
                    // 依旧有问题
                    char buffer[1024];
                    size_t n = recv(sock, buffer, sizeof(buffer) - 1, 0);
                    if (n > 0)
                    {
                        buffer[n] = 0;
                        logMessage(DEBUG, "client# %s", buffer);
                        std::string response = _func(buffer);
                        send(sock, response.c_str(), response.size(), 0);
                    }
                    else if (n == 0)
                    {
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                        close(sock);
                        logMessage(NORMAL, "client quit");
                    }
                    else
                    {
                        epoll_ctl(_epfd, EPOLL_CTL_DEL, sock, nullptr);
                        close(sock);
                        logMessage(ERROR, "recv error, code: %d, errstring: %s", errno, strerror(errno));
                    }
                }
                else
                {
                }
                logMessage(DEBUG, "HandlerEvent out");
            }
        }
        ~EpollServer()
        {
        }

    private:
        int _listenSock;
        uint16_t _port;
        func_t _func;
        int _epfd;
        struct epoll_event *_revs;
        int _num;
    };

}